热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

手指触控|Android电容屏幕驱动调试指南

篇首语:本文由编程笔记#小编为大家整理,主要介绍了android 电容屏驱动调试相关的知识,希望对你有一定的参考价值。 一、总体架构 硬件部分:先看一个总体的图吧,其实触摸

篇首语:本文由编程笔记#小编为大家整理,主要介绍了android 电容屏驱动调试相关的知识,希望对你有一定的参考价值。


一、总体架构

硬件部分:先看一个总体的图吧,其实触摸屏原理也比较简单,触摸屏和主控芯片间的联系,如下主要有三部分:


1、IIC部分,初始化gt8105的数据和传回主控制的坐标位置信息就是通过IIC这条线传输的;

2、INT,当gt8105初触摸时,会发出中断通知主控接收信息(坐标数据);

3、gt8105电源、复位这一部分,不同芯片有所不同,可以根据触摸屏芯片来配置。

 软件部分:

 二、电容触摸屏的主要参数

   
1、IIC
(1)、clk 370KHz~400KHz;
(2)、触摸屏工作在从模式,这个比较简单;
2、电容检测频率,也就是每秒检测的次数:(大概)
(1)、单指≥100Hz;
(2)、五指≥80Hz;
(3)、十指≥60Hz。
3、手指按下,没抬起时触发多少中断?
            中断个数也就是检测频率,按下没提起一直有中断。这样我们就可有判断单点、划线之类的操作;
4、校准功能、自动校准(有个别电容屏没有的,用软件校准)
(1)、初始化校准
             不同的温度、湿度及物理空间结构均会影响到电容传感器在闲置状态的基准值。一般电容触摸屏会在初始化的 200ms内根据环境情况自动获得新的检测基准。完成触摸屏检测的初始化。
(2)、 自动温漂补偿
              温度、湿度或灰尘等环境因素的缓慢变化,也会影响到电容传感器在闲置状态的基准值。实时检测各点数据的变化,对历史数据进行统计分析,由此来修正检测基准。从而降低环境变化对触摸屏检测的影响。    
5、推荐工作条件(环境温度为 25°C,VDD=2.8V)

                 参数                                最小值     典型值     最大值     单位

         模拟AVDD(参考AGND)           2.5          2.8          3.6           V  

        数字DVDD(参考DGND)           2.5          2.8          3.6           V

        电源纹波                                 50(注意电池、充电器的影响)  mV

      工作温度                                  -20         +25             +85        度

     工作湿度                                  -              -                  95      %

三、硬件接口电路:

如下图:

SDA    IIC数据 要上拉电阻,为1K;

SCL     IIC 时钟(400KHz)

TP_EN    使能脚(gt8105为高电平)

INT      中断(一直点到触摸屏时中断是一直发出的)

VCC    3.3V 这个电压一直有

GND        地

软件部分,整体流程如下:

三、IIC配置

                设备到芯片的数据、初始化值都是从这条总线上传输的,首先我们要配置这个条总线,

/linux/arch/arm/mach-exynos/mach-smdkv310.c,这个因平台而已,地址右移也跟情况而定,如果本来就是7bit的地址就不用移位。

static struct i2c_board_info i2c_devs5[] __initdata =
#if CONFIG_TOUCHSCREEN_GT8105
         
                    I2C_BOARD_INFO("Goodix-TS", (0xaa>>1)),
                    .irq = IRQ_EINT(5),
         
#endif
;

四、电源、复位(使能脚)

1、电源

          3.3V的电源是一直有的,这个硬件上给就行了。

2、复位(时能脚),这个因触摸屏而已,gt8105工作时要高电平。

在:linux3.0/drivers/input/touchscreen/goodix_touch.h中

#define          RESETPIN_CFG          s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_OUTPUT)
#define          RESETPIN_SET0           gpio_direction_output(EXYNOS4_GPB(4),0)
#define          RESETPIN_SET1          gpio_direction_output(EXYNOS4_GPB(4),1)
static void goodix_reset(void)

          int err;
          err = gpio_request(EXYNOS4_GPB(4), "GPX1");
          if (err)
          printk(KERN_ERR "#### failed to request GPB_4 ####\\n");
          RESETPIN_CFG; //配置管脚功能
          RESETPIN_SET0;//管脚拉低
          mdelay(20); //延时
          RESETPIN_SET1;//管脚拉高
          mdelay(60);
          gpio_free(EXYNOS4_GPB(4));

五、中断配置

在:linux3.0/drivers/input/touchscreen/goodix_touch.h中

#define INT_PORT EXYNOS4_GPX0(5)
#ifdef INT_PORT
          #define TS_INT                     IRQ_EINT(5)//中断引脚,中断号          
          #define INT_CFG           S3C_GPIO_SFN(0x0F)                                                  
#else
 
在:linux3.0/drivers/input/touchscreen/goodix_touch.h中 中断申请
#ifdef INT_PORT
          client->irq=TS_INT;
          if (client->irq) 
         
             ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,client->name, ts);
#endif
  上面三部完成了触摸屏工作的最基本配置,保证IIC、上电、INT正常,触摸屏就可以工作。

六、驱动程序分析(完整代码见 goodix_touch.c/goodix_touch.h)

               驱动有几个比较重要的部分:probe函数分析;中断申请、工作队列调度;中断下半部函数的执行,坐标值计算、上报。

1、probe函数分析

static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)

          struct goodix_ts_data *ts;
          …………
          // 1,分配触摸屏结构内核空间;
          ts = kzalloc(sizeof(*ts), GFP_KERNEL); 
          …………
          // 2,初始化工作队列,这个比较重要,中断触发后,调用队列中的goodix_ts_work_func函数,计算上报坐标值;
          INIT_WORK(&ts->work, goodix_ts_work_func); 
          …………
          // 3, 触摸芯片初始化;
          for(retry&#61;0; retry<3; retry&#43;&#43;)
         
                    ret&#61;goodix_init_panel(ts);
          …………
         
          //4、触摸屏复位&#xff0c;拉高&#xff1b;
          goodix_reset();                     
#ifdef INT_PORT
          // 5,中断申请&#xff0c;TS_INT就是我们所设定的中断脚&#xff1b;
          client->irq&#61;TS_INT;                                                            
                    ret &#61; request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
                              client->name, ts);
          ………………
#endif
 
          // 6、分配input驱动内核空间&#xff1b;
          ts->input_dev &#61; input_allocate_device(); 

  // 7,input初始化参数设定&#xff0c;我们在前面提到Linux与android 多点触摸协议里有对这部分说明&#xff1b;
          ts->input_dev->evbit[0] &#61; BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
          ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] &#61; BIT_MASK(BTN_TOUCH);
          ts->input_dev->absbit[0] &#61; BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);                                                             // absolute coor (x,y)
#ifdef HAVE_TOUCH_KEY
          for(retry &#61; 0; retry          
                    input_set_capability(ts->input_dev,EV_KEY,touch_key_array[retry]);          
         
#endif
 
          input_set_abs_params(ts->input_dev, ABS_X, 0, ts->abs_x_max, 0, 0);
          input_set_abs_params(ts->input_dev, ABS_Y, 0, ts->abs_y_max, 0, 0);
          input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);
          //8、这部分针对触摸屏参数设定&#xff1b;
#ifdef GOODIX_MULTI_TOUCH
          input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
          input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
          input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
          input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
          input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, ts->max_touch_num, 0, 0);
#endif          
          //9、触摸屏版本信息设定&#xff1b;
          sprintf(ts->phys, "input/ts");
          ts->input_dev->name &#61; goodix_ts_name;
          ts->input_dev->phys &#61; ts->phys;
          ts->input_dev->id.bustype &#61; BUS_I2C;
          ts->input_dev->id.vendor &#61; 0xDEAD;
          ts->input_dev->id.product &#61; 0xBEEF;
          ts->input_dev->id.version &#61; 10427;          //screen firmware version
       

  //10,对于input子系统来说&#xff0c;这个是重头戏了&#xff0c;只有注册了input子系统&#xff0c;其他的才有做用&#xff1b;
          ret &#61; input_register_device(ts->input_dev); 
          ………………
          // 11,对睡眠唤醒操作&#xff1b;
#ifdef CONFIG_HAS_EARLYSUSPEND 
          ts->early_suspend.level &#61; EARLY_SUSPEND_LEVEL_BLANK_SCREEN &#43; 1;
          ts->early_suspend.suspend &#61; goodix_ts_early_suspend;
          ts->early_suspend.resume &#61; goodix_ts_late_resume;
          register_early_suspend(&ts->early_suspend);
#endif
………………


&#xff08;1&#xff09;、分配触摸屏结构内核空间&#xff1b;

struct goodix_ts_data
          uint16_t addr;
          uint8_t bad_data;
          struct i2c_client *client;
          struct input_dev *input_dev;
          int use_reset;                    //use RESET flag
          int use_irq;                    //use EINT flag
          int read_mode;                    //read moudle mode,20110221 by andrew
          struct hrtimer timer;
          struct work_struct work;
          char phys[32];
          int retry;
          struct early_suspend early_suspend;
          int (*power)(struct goodix_ts_data * ts, int on);
          uint16_t abs_x_max;
          uint16_t abs_y_max;
          uint8_t max_touch_num;
          uint8_t int_trigger_type;
          uint8_t green_wake_mode;
;

&#xff08;2&#xff09;、初始化工作队列&#xff0c;这个比较重要&#xff0c;中断触发后&#xff0c;调用队列中的goodix_ts_work_func函数&#xff0c;计算上报坐标值&#xff1b;这个和中断申请一起分析&#xff1b;

&#xff08;3&#xff09;、触摸芯片初始化&#xff1b;

          对触摸芯片寄存器的初始化&#xff0c;这里面对中断方式设定等&#xff0c;一般芯片厂的FAE在调试的时候会修改这里面的值&#xff0c;这个也是因芯片而异&#xff0c;有的在驱动里做&#xff0c;可以直接改&#xff1b;有的直接做成固件了&#xff0c;那部分要FAE帮忙了。

uint8_t cfg_info_group1[] &#61; 
                  
             0x65,0x00,0x25,0x80,0x19,0x00,0x00,0x2C,0x11,0x11,0x32,0x02,0x08,0x10,0x20,0x00,
             0x00,0x88,0x88,0x88,0x03,0x13,0x32,0x64,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
             0x08,0x09,0x0A,0x0B,0x0C,0xFF,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
             0x17,0x18,0x19,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
             0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
             0x00,0x00,0x00,0x00
          ;
&#xff08;4&#xff09;、触摸屏复位&#xff0c;拉高&#xff1b;

          gt8015在工作时要拉高&#xff0c;所以我们做一个拉低—延时--拉高的操作&#xff1b;

&#xff08;5&#xff09;、中断申请&#xff0c;TS_INT就是我们所设定的中断脚&#xff0c;和&#xff08;2&#xff09;一起后面分析&#xff1b;

&#xff08;6&#xff09;、分配input驱动内核空间&#xff1b;

          ts->input_dev&#61; input_allocate_device();
&#xff08;7&#xff09;、input初始化参数设定&#xff0c;我们在前面提到Linux与Android 多点触摸协议里有对这部分说明&#xff1b;&#xff08;8&#xff09;、这部分针对触摸屏参数设定&#xff1b;

&#xff08;9&#xff09;、触摸屏版本信息设定&#xff1b;

cat /proc/bus/input/devices时可以看到下面信息&#xff08;这个是pixcir的触摸屏&#xff09;
I: Bus&#61;0018 Vendor&#61;0000 Product&#61;0000 Version&#61;0000
N: Name&#61;"pixcir-ts"
P: Phys&#61;
S: Sysfs&#61;/devices/platform/s3c2440-i2c.5/i2c-5/5-005c/input/input3
U: Uniq&#61;
H: Handlers&#61;kbd event3 
B: PROP&#61;0
B: EV&#61;b
B: KEY&#61;400 0 0 0 0 1000 40000800 0 0 0 0
B: ABS&#61;2650000 1000000
&#xff08;10&#xff09;、对于input子系统来说&#xff0c;这个是重头戏了&#xff0c;驱动注册到input子系统&#xff1b;

        input_register_device(ts->input_dev);
&#xff08;11&#xff09;&#xff0c;触摸屏睡眠唤醒操作&#xff0c;这部分不做详细说明&#xff0c;感兴趣的可以看下……

2、中断申请、工作队列调度

&#xff08;1&#xff09;、中断申请

                 ret &#61; request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
                              client->name, ts);
第一个参数&#xff1a; 中断号&#xff0c;client->irq&#xff0c;client->irq&#61;TS_INT;
#define TS_INT                     IRQ_EINT(5)对应到我们要申请的中断&#xff1b;
第二个参数&#xff1a;中断执行函数&#xff0c;goodix_ts_irq_handler &#xff1b;
第三个参数&#xff1a;中断触发方式&#xff1a;上升沿触发、下降沿触发、高电平触发、低电平触发
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_EDGE_FALLING,
IRQ_TYPE_LEVEL_LOW,
IRQ_TYPE_LEVEL_HIGH
第四个参数&#xff1a;
第五个参数&#xff1a;
&#xff08;2&#xff09;、中断处理函数 goodix_ts_irq_handler

static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)

          struct goodix_ts_data *ts &#61; dev_id;
          queue_work(goodix_wq, &ts->work);
          return IRQ_HANDLED;

看下queue_work()这个函数中的两个参数&#xff1a;

a、goodix_wq


          goodix_wq&#61;create_singlethread_workqueue("goodix_wq");                    //createa work queue and worker thread
在函数 goodix_ts_init中&#xff0c;创建工作队列和工作线程,初始化时创建线程。

b、&ts->work

            在函数goodix_ts_probe&#xff08;&#xff09;中&#xff1a;


INIT_WORK(&ts->work,goodix_ts_work_func);

           在工作队列&ts->work中增加 goodix_ts_work_func任务。
          也就是当中断函数触发时&#xff0c;执行中断函数goodix_ts_irq_handler&#xff08;&#xff09;&#xff0c;中断函数里面对队列调度&#xff0c;调用队列中的goodix_ts_work_func&#xff08;&#xff09;函数。


3、中断下半部函数的执行goodix_ts_work_func&#xff08;&#xff09;函数

这就是核心部分&#xff0c;坐标点的计算、上报、多点处理都在这个函数中执行。

static void goodix_ts_work_func(struct work_struct *work)
         
          int ret&#61;-1;
          int tmp &#61; 0;
          uint8_t point_data[(1-READ_COOR_ADDR)&#43;1&#43;2&#43;5*MAX_FINGER_NUM&#43;1]&#61; 0 ; //read address(1byte)&#43;key index(1byte)&#43;point mask(2bytes)&#43;5bytes*MAX_FINGER_NUM&#43;coor checksum(1byte)
          uint8_t check_sum &#61; 0;
          uint16_t finger_current &#61; 0;
          uint16_t finger_bit &#61; 0;
          unsigned int count &#61; 0, point_count &#61; 0;
          unsigned int position &#61; 0;          
          uint8_t track_id[MAX_FINGER_NUM] &#61; 0;
          unsigned int input_x &#61; 0;
          unsigned int input_y &#61; 0;
          unsigned int input_w &#61; 0;
          unsigned char index &#61; 0;
          unsigned char touch_num &#61; 0;
           
          struct goodix_ts_data *ts &#61; container_of(work, struct goodix_ts_data, work);
 
 
          if(g_enter_isp)return;
 
          COORDINATE_POLL:
          if((ts->int_trigger_type> 1)&& (gpio_get_value(INT_PORT) !&#61; (ts->int_trigger_type&0x01)))
         
                    goto NO_ACTION;
                             
 
          if( tmp > 9)
                     
                    dev_info(&(ts->client->dev), "I2C transfer error,touchscreen stop working.\\n");
                    goto XFER_ERROR ;
         
           
          if(ts->bad_data)          
                    msleep(20);
           
          point_data[0] &#61; READ_COOR_ADDR;                    //read coor address
          //1、读取触摸屏值&#xff0c;手指数、坐标值等&#xff1b;
          ret&#61;i2c_read_bytes(ts->client, point_data, ((1-READ_COOR_ADDR)&#43;1&#43;2&#43;5*ts->max_touch_num&#43;1));
          …………
          //2、判断是否有手指按下&#xff1b;
          finger_current &#61; (point_data[3 - READ_COOR_ADDR]<<8) &#43; point_data[2 – READ_COOR_ADDR];
           
          if(finger_current)//3、如果有手指按下
                   
                    point_count &#61; 0, finger_bit &#61; finger_current;
                    //3&#xff0c;循环判断有多少手指按下&#xff1b;
                    for(count &#61; 0; (finger_bit !&#61; 0) && (count max_touch_num); count&#43;&#43;)//cal how many point touch currntly
                   
                              if(finger_bit & 0x01)
                             
                                        track_id[point_count] &#61; count;
                                        point_count&#43;&#43;;
                             
                              finger_bit >>&#61; 1;
                   
                    //4、把按下手指数赋给touch_num&#xff1b;
                    touch_num &#61; point_count;
                    //5、计算坐标值&#xff1b;
                    check_sum &#61; point_data[2 - READ_COOR_ADDR] &#43; point_data[3 - READ_COOR_ADDR];                               //cal coor checksum
                    count &#61; 4 - READ_COOR_ADDR;
                    for(point_count *&#61; 5; point_count > 0; point_count--)
                              check_sum &#43;&#61; point_data[count&#43;&#43;];
                    check_sum &#43;&#61; point_data[count];
                    if(check_sum !&#61; 0)                              //checksum verify error
                   
                              printk("coor checksum error!\\n");
                              if(ts->int_trigger_type> 1)
                                        goto COORDINATE_POLL;
                              else          
                                        goto XFER_ERROR;
                   
         
          //6、读取值坐标值上报&#xff1b;
          if(touch_num)
         
                    //7、touch_num为按下手指个数&#xff0c;依次循环读取&#xff1b;
                    for(index&#61;0; index                    
                              position &#61; 4 - READ_COOR_ADDR &#43; 5*index;
                              //8、读出X的值&#xff1b;
                              input_x &#61; (unsigned int) (point_data[position]<<8) &#43; (unsigned int)( point_data[position&#43;1]);
                              //9、读出Y的值&#xff1b;
                              input_y &#61; (unsigned int)(point_data[position&#43;2]<<8) &#43; (unsigned int) (point_data[position&#43;3]);
                              input_w &#61;(unsigned int) (point_data[position&#43;4]);                    
                              //10、如果读出值超出范围&#xff0c;退出&#xff1b;
                              if((input_x > ts->abs_x_max)||(input_y > ts->abs_y_max))
                              continue;
                              //11、下面的函数依次上报坐标&#xff0c; input_mt_sync单点同步
                              input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
                              input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);                              
                              input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
                              input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
                              input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, track_id[index]);
                              input_mt_sync(ts->input_dev);
                   
         
          //12、没有触摸时&#xff0c;初始值为0&#xff1b;
          else
         
                    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
                    input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
                    input_mt_sync(ts->input_dev);
         
          //13、同步多点值&#xff1b;
          input_sync(ts->input_dev);
 
          if(ts->int_trigger_type> 1)
         
                    msleep(POLL_TIME);
                    goto COORDINATE_POLL;
         
          goto END_WORK_FUNC;
 
          NO_ACTION:          
          END_WORK_FUNC:
          XFER_ERROR:
                     
          return;

                总的来数&#xff0c;当我们手指按下是&#xff0c;不管是单个手指&#xff0c;还是多个手指&#xff0c;坐标值和一些信息存储到触摸芯片的相应寄存器中&#xff0c;然后再通过IIC读出&#xff0c;送到主控中就可以了&#xff0c;其他事情就是android去处理了。

           如下图所示&#xff0c;规格书中坐标及重量&#xff1a;XY坐标缓存寄存器的高低位&#xff1a;

中断触发--中断函数--工作队列调度--功能函数执行
 


推荐阅读
author-avatar
手机用户2602933165
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有